Google VR SDK 示例 360 media
文章目录
Google VR SDK 示例代码全景和视频
Google的SDK示例代码中有两个应用 simplepanowidget和simlevrvideo展示了如何内嵌一个360度的图片或者是视频。
什么是360 media
360度媒介,包括360度全景图片和360度全景视频。通过他们,可以加强传统应用的沉浸式体验。例如可以在旅游类应用中添加这种视图查看器作为海底世界游览体验,在家装应用中,让消费者可以先体验一下虚拟的效果。
这些360度媒介支持立体变化并与Google cardboard等vr平台兼容,也支持在浏览器中或者移动应用中查看而不需要特定的vr硬件支持。
常见格式
360度媒体的格式可以是 mono或者是stereo。图片和视频通常需要存储在equirectangular-panoramic (equirect-pano)格式中,可以理解为柱体全景格式,这种格式为大部分拍摄解决方案所支持的格式。
Mono 360使用一张全景,stero 360使用两张堆积的全景图片。stero在全景之上,还有一个景深的这样一个概念,我们对前景和背景的距离深度有了一个感官的体验。
360度图片
可以以png,jpeg,gif的格式进行存储,建议使用jpeg来提高压缩率
为了最大限度的提高兼容性和性能,需要的尺寸是2次幂,2024,4096这样
mono图片,单张的方案,需要2:1的宽高比 例如4096*4096
stereo图片,左右两张堆积方案的,需要1:1的宽高比 4096*4096
360度视频
以h2642编码的mp4s格式存储
mono方案提供2:1宽高比
stereo提供1:1宽高比
一些比较老的设备无法对大雨1080p(1920*1080)的视频进行解码,如果要进行兼容,建议提供提供monoscopic 1920 * 1080的视频和stereo 2048 * 2048的的视频
如何内嵌和显示这些媒体
另外也有ios平台等
如何拍摄到全景的媒体
实景拍摄
- Cardboard Camera App: 使用该应用可以快速的拍摄360全景图片,然后可以下载 download 这些图片然后使用 conversion tool 来生成 stereo 360° 图片,就可以符合 Cardboard’s 图片要求了。
- Ricoh Theta: 可用于拍摄 mono 360° 图片和视频
CG capture
cgi软件可根据生成全景图片和视频,一些热门的拍摄方案如下
- 360 Panorama Capture for Unity: A free, easy-to-use 360° capture plugin for Unity.
- Unreal: Stero panoramic capture in Unreal.
- (Unsupported) Domemaster3D: A free solution for capturing mono and stereo 360° images from Maya / Autodesk 3ds Max.
- Renderman: Open-source library for capturing 360° content.开源库
- Rendering Omnidirectional Stereo Content: A whitepaper for anyone interested in writing their own 360° capture solutions.
YouTube下载,在YouTube上搜索monoscopic的视频,然后通过 http://youtubemp4.to/ 来下载mp4格式的文件
全景图片walkthrough
根据Gsensor的数据展示不同的方位景物;
全屏模式 和 cardboard 模式切换
代码概览
在layout XML文件中,嵌入,该组件自身就集成了全屏,立体模式,退出等模式的切换按钮
1
2
3
4
5
6<com.google.vr.sdk.widgets.pano.VrPanoramaView
android:id="@+id/pano_view"
android:layout_margin="5dip"
android:layout_width="match_parent"
android:scrollbars="@null"
android:layout_height="250dip"/>activitie 代码
初始化
1
2
3
4
5
6
7
8
9
10
11@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main_layout);
.......
panoWidgetView = (VrPanoramaView) findViewById(R.id.pano_view);
panoWidgetView.setEventListener(new ActivityEventListener());
// Initial launch of the app or an Activity recreation due to rotation.
handleIntent(getIntent());
}其中ActivityEventListener继承自VrPanoramaEventListener,用于监听来自widget的事件,例如当widget加载完图片后的onLoadSuccess回调。或者加载失败后的onLoadError回调。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23/**
* Listen to the important events from widget.
*/
private class ActivityEventListener extends VrPanoramaEventListener {
/**
* Called by pano widget on the UI thread when it's done loading the image.
*/
@Override
public void onLoadSuccess() {
loadImageSuccessful = true;
}
/**
* Called by pano widget on the UI thread on any asynchronous error.
*/
@Override
public void onLoadError(String errorMessage) {
loadImageSuccessful = false;
Toast.makeText(
SimpleVrPanoramaActivity.this, "Error loading pano: " + errorMessage, Toast.LENGTH_LONG)
.show();
Log.e(TAG, "Error loading pano: " + errorMessage);
}在线程中加载图片
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43/**
* Helper class to manage threading.
*/
class ImageLoaderTask extends AsyncTask<Pair<Uri, Options>, Void, Boolean> {
/**
* Reads the bitmap from disk in the background and waits until it's loaded by pano widget.
*/
@Override
protected Boolean doInBackground(Pair<Uri, Options>... fileInformation) {
Options panoOptions = null; // It's safe to use null VrPanoramaView.Options.
InputStream istr = null;
if (fileInformation == null || fileInformation.length < 1
|| fileInformation[0] == null || fileInformation[0].first == null) {
AssetManager assetManager = getAssets();
try {
istr = assetManager.open("andes.jpg");//打开assert文件
panoOptions = new Options();
panoOptions.inputType = Options.TYPE_STEREO_OVER_UNDER;
} catch (IOException e) {
Log.e(TAG, "Could not decode default bitmap: " + e);
return false;
}
} else {
try {
istr = new FileInputStream(new File(fileInformation[0].first.getPath()));
panoOptions = fileInformation[0].second;
} catch (IOException e) {
Log.e(TAG, "Could not load file: " + e);
return false;
}
}
panoWidgetView.loadImageFromBitmap(BitmapFactory.decodeStream(istr), panoOptions);//将读取的iostream进行加载
try {
istr.close();
} catch (IOException e) {
Log.e(TAG, "Could not close input stream: " + e);
}
return true;
}
}
全景视频walkthrough
全景视频的视图和全景图片的非常相似,使用上也差不多,展现出来的,就是一个是视频画面生动的效果
XML集成:
1 | <com.google.vr.sdk.widgets.video.VrVideoView |
初始化
1 | // Bind input and output objects for the view. |
其中ActivityEventListener
1 | /** |
加载视频的线程
1 | /** |
总结
这两个应用主要展示 VrPanoramaView 和VrVideoView的基本用法
番外示例video360和videoplayer
sdk-video360
video360要求设备最低版本为android 24,android N 7.0以上
可以渲染全景视频的播放器。 根据intent中的文件uri来进行进行视频播放。应用中定义了两个activity,一个只能在2d的launcher中显示图标,另外一个只能在专属的Daydream Home中显示图标
1 | <!-- This is a 2D Version of the video player. --> |
其中activity的大部分代码都是和权限相关的,真正的视频解析加载在MediaLoader中,从类的说明中可以看到,可以通过adb命令来传递intent来打开视频:
1 | <p>Example intents compatible with adb are: |
我们从YouTube上下载了一个monoscopic的视频,放在sdcard的目录下,通过运行命令可播放对应的全景视频
1 | F:\09androidsdk>adb shell am start -a android.intent.action.VIEW -n com.google.v |
该命令启用的是VideoActivity来播放全景视频,参数stereoFormat 0表示,视频类型为单个摄像头帧拍摄的全景视频。1表示用左右眼的方式渲染的,如果在非vr的显示中显示的话,则只显示左眼部分。2表示上下部分分割的左右眼渲染方式,如果在非vr显示中显示的话,只显示上部分内容
1 | /** Standard media where a single camera frame takes up the entire media frame. */ |
播放器demo在8996上 android6.0无法运行。
在8953上可以运行播放3d stereo视频,视频播放不正常,叠加不正确。
但是切换成cardboard模式的点击 眼镜 标示的图标按钮后,切换到VrVideoActivity提示:
手机不兼容:手机必须与Daydream兼容,请访问Daydream帮助中心了解详情。
在moto z和pixel等兼容手机上可正常运行,实现左右眼形变播放,中间会弹出和daydream控制器的配对的等。
对应配合Daydream viewer应该就可以看到立体视频效果。
TODO: 如何与Daydream平台进行兼容,需要做哪些工作,目前官网上列出的课兼容手机有华为mate,三星galaxy note8,pixel,moto z等手机。
sdk-videoplayer
通过 Asynchronous Reprojection Video Surface API来播放视频,也是一个播放器。
在5516上,运行出错,暂时不研究了